package cn.iocoder.yudao.module.design.service.node;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.design.controller.admin.flow.vo.FlowBaseVO;
import cn.iocoder.yudao.module.design.controller.admin.house.vo.HouseRespVO;
import cn.iocoder.yudao.module.design.controller.admin.node.vo.*;
import cn.iocoder.yudao.module.design.convert.node.NodeConvert;
import cn.iocoder.yudao.module.design.dal.dataobject.flow.FlowDO;
import cn.iocoder.yudao.module.design.dal.dataobject.flowmd.FlowMdDO;
import cn.iocoder.yudao.module.design.dal.dataobject.houseUserRel.HouseUserRelDO;
import cn.iocoder.yudao.module.design.dal.dataobject.node.NodeDO;
import cn.iocoder.yudao.module.design.dal.dataobject.pic.PicDO;
import cn.iocoder.yudao.module.design.dal.dataobject.userflowrel.UserFlowRelDO;
import cn.iocoder.yudao.module.design.dal.mysql.flow.FlowMapper;
import cn.iocoder.yudao.module.design.dal.mysql.flowmd.FlowMdMapper;
import cn.iocoder.yudao.module.design.dal.mysql.houseUserRel.HouseUserRelMapper;
import cn.iocoder.yudao.module.design.dal.mysql.node.NodeMapper;
import cn.iocoder.yudao.module.design.dal.mysql.userflowrel.UserFlowRelMapper;
import cn.iocoder.yudao.module.design.service.flow.FlowService;
import cn.iocoder.yudao.module.design.service.flowmd.FlowMdService;
import cn.iocoder.yudao.module.design.service.flowtask.FlowTaskServiceImpl;
import cn.iocoder.yudao.module.design.service.house.HouseServiceImpl;
import cn.iocoder.yudao.module.design.service.house.bo.NodeItemDataBO;
import cn.iocoder.yudao.module.design.service.pic.PicService;
import cn.iocoder.yudao.module.design.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.design.enums.design.FlowCdEnum;
import cn.iocoder.yudao.module.design.enums.design.UserFlowRelStatusCdEnum;
import cn.iocoder.yudao.module.design.enums.design.UserRelStatusCdEnum;
import cn.iocoder.yudao.module.design.enums.user.DesignUserRoleEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.design.enums.ErrorCodeConstants.NODE_NOT_EXISTS;

/**
 * 任务节点信息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
@Lazy
public class NodeServiceImpl implements NodeService {

    @Resource
    private NodeMapper nodeMapper;

    @Resource
    private UserFlowRelMapper userFlowRelMapper;


    @Resource
    private HouseUserRelMapper houseUserRelMapper;



    @Resource
    @Lazy
    HouseServiceImpl houseService;

    @Resource
    private PicService picService;

    @Resource
    private FlowMapper flowMapper;

    @Resource
    @Lazy
    private FlowService flowService;
    @Resource
    private FlowMdMapper flowMdMapper;

    @Resource
    private FlowMdService flowMdService;

    @Resource
    @Lazy
    FlowTaskServiceImpl flowTaskService ;




    @Override
    public Long createNode(NodeCreateReqVO createReqVO) {
        // 插入
        NodeDO node = NodeConvert.INSTANCE.convert(createReqVO);
        node.setDeleted(false);
        nodeMapper.insert(node);
        // 返回
        return node.getId();
    }

    @Override
    public void updateNode(NodeUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateNodeExists(updateReqVO.getId());
        // 更新
        NodeDO updateObj = NodeConvert.INSTANCE.convert(updateReqVO);
        nodeMapper.updateById(updateObj);
    }

    @Override
    public void updateNodeDealerId(Long houseId, Long oldUserId, Long newUserId) {
        QueryWrapper<NodeDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("house_id",houseId);
        queryWrapper.eq("dealer_id",oldUserId);
        NodeDO  nodeDO = new NodeDO();
        nodeDO.setDealerId(newUserId);
        // 更新
        nodeMapper.update(nodeDO,queryWrapper);
    }
    @Override
    public void deleteNode(Long id) {
        // 校验存在
        this.validateNodeExists(id);
        // 删除
        nodeMapper.deleteById(id);
    }
    /**
     * 删除flowId 下所有节点
     * @author Annie
     * @time 2023/9/30 10:04
     * @param[1] flowId
     * @throws
     */
    @Override
    public void deleteNodeByFlowId(Long flowId) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("flow_id",flowId);
        nodeMapper.delete(queryWrapper);
    }

    public void validateNodeExists(Long id) {
        if (nodeMapper.selectById(id) == null) {
            throw exception(NODE_NOT_EXISTS);
        }
    }

    @Override
    public NodeDO getNode(Long id) {
        return nodeMapper.selectById(id);
    }

    @Override
    public List<NodeDO> getNodeList(Collection<Long> ids) {
        return nodeMapper.selectBatchIds(ids);
    }

//    @Override
//    public List<NodeListVo> getNodeList(NodeBaseVO nodeBaseVO) {
//        // 查询出所有流程数据
//        final List<NodeDO> nodeDos = nodeMapper.selectList(nodeBaseVO);
//        final List<NodeListVo> childData = getChildData(nodeDos);
//        System.out.println(childData);
//        return  childData;
//    }
    @Override
    public List<NodeListVo> getNodeList(NodeBaseVO nodeBaseVO) {
        // 查询出所有Node数据
        Long flowId = nodeBaseVO.getFlowId();
        final List<NodeDO> nodeDosList = nodeMapper.selectListByFlowId(flowId);
        // 进行数据筛选   1.preId ==0 的筛选出来
        List<NodeDO> preNodeList = nodeDosList.stream()
                .filter(node -> node.getPreId() == 0)
                .collect(Collectors.toList());
//        2.循环筛选preId = item.id
        List<NodeListVo> childData =  getChildData(preNodeList,nodeDosList);

        return  childData;
    }

    @Override
    public List<NodeListVo> getNodeList2(NodeBaseVO nodeBaseVO) {
        // 查询出所有Node数据
        Long flowId = nodeBaseVO.getFlowId();
        final List<NodeDO> nodeDosList = nodeMapper.selectListByFlowId(flowId);
        // 进行数据筛选   1.preId ==0 的筛选出来
        List<NodeDO> preNodeList = nodeDosList.stream()
                .filter(node -> node.getPreId() == 0)
                .collect(Collectors.toList());
//        2.循环筛选preId = item.id
        List<NodeListVo> childData =  getChildData(preNodeList,nodeDosList);

        return  childData;
    }

    public  List<NodeListVo>  getChildData(List<NodeDO> preNodeList,List<NodeDO> nodeDosList){
        List<NodeListVo> resultList = new ArrayList<>();


        for (NodeDO nodeDO:preNodeList   ) {
            NodeListVo nodeListVo = NodeConvert.INSTANCE.convertNodeListVo(nodeDO);
            List<NodeDO> nodeDOList = nodeDosList.stream()
                    .filter(node -> nodeDO.getId().toString().equals( node.getPreId().toString()) )
                    .collect(Collectors.toList());

            if(nodeDOList.size()>0){
                nodeListVo.setItems( getChildData(nodeDOList,nodeDosList));
            }
            resultList.add(nodeListVo);
        }
        return resultList;
    }
    @Override
    public List<NodeDO> getToDoTaskList(NodeBaseVO nodeBaseVO) {
        // 根据房主 设计师 查询房子 id
        QueryWrapper<NodeDO> queryWrapper = new QueryWrapper<NodeDO>();
        queryWrapper.eq("status_cd","1");
        queryWrapper.ne("pre_id","0");
        return  nodeMapper.selectList(queryWrapper);
    }

    @Override
    public void purchaseNodeTask(NodePurchaseVO baseVO) {



    }

    public  List<NodeListVo>  getChildData(List<NodeDO> nodeDOS){
        List<NodeListVo> resultList = new ArrayList<>();


        for (NodeDO nodeDo:nodeDOS ) {
            NodeListVo nodeListVo = NodeConvert.INSTANCE.convertNodeListVo(nodeDo);
            List<NodeDO> nodeChilds = nodeMapper.selectList("pre_id", nodeListVo.getId());
            if(nodeChilds.size()>0){
                nodeListVo.setItems( getChildData(nodeChilds));
            }
            resultList.add(nodeListVo);
        }
        return resultList;
    }
    @Override
    public PageResult<NodeDO> getNodePage(NodePageReqVO pageReqVO) {
        return nodeMapper.selectPage(pageReqVO);
    }

    @Override
    public List<NodeDO> getNodeList(NodeExportReqVO exportReqVO) {
        return nodeMapper.selectList(exportReqVO);
    }

    /**
     * 批量创建采购流程
     */
    @Override
    public void createPurchaseNode(NodePurchaseVO baseVO) {

        // 判断采购材料是否为空
        List<CommonVo> purchaseList = baseVO.getPurchaseList();
        if (CollUtil.isEmpty(purchaseList)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PURCH_ITEM_NOT_NULL);
//            throw new NullPointerException("采购材料不能为空");
        }
        // 查询项目信息
        HouseRespVO house = houseService.getHouseById(baseVO.getHouseId());
        // 查询采购流程信息
        FlowDO flowDO = flowMapper.selectOne(Wrappers.<FlowDO>lambdaQuery()
                .eq(FlowDO::getHouseId, baseVO.getHouseId())
                .eq(FlowDO::getFlowCd, "1"));
        // 查询采购流程模板
        FlowMdDO flowMdDO = flowMdMapper.selectOne(Wrappers.<FlowMdDO>lambdaQuery()
                .eq(FlowMdDO::getFlowCd, "1")
                .eq(FlowMdDO::getId, "4"));
        // 获取子节点模板
        String nextIds = flowMdDO.getChildren();
        int cgIndex = nextIds.indexOf("采");
        String substring = "";
        if (cgIndex >= 0) {
            substring = nextIds.substring(cgIndex, cgIndex + 4);
        }
        // 查询所有采购流程
        List<NodeDO> nodeList = nodeMapper.selectList(Wrappers.<NodeDO>lambdaQuery()
                .eq(NodeDO::getPreId, 0L)
                .eq(NodeDO::getFlowId, flowDO.getId()));
        Long aLong = (long) nodeList.size();
        // 获取sordId 初始值
        int index = aLong.intValue() + 1;
        for (CommonVo item : purchaseList) {
            String nodeName = "采购" + item.getName();
            String subNextIds = nextIds;
            if (StrUtil.isNotEmpty(substring)) {
                subNextIds = nextIds.replaceAll(substring, nodeName);
            }
            NodeDO nodeDO = new NodeDO();
            nodeDO.setPreId(0L);
            nodeDO.setFlowId(flowDO.getId());
            nodeDO.setHouseId(flowDO.getHouseId());
            nodeDO.setSortId(String.valueOf(index));
            nodeDO.setDesignerId(flowDO.getDesignerId());
            nodeDO.setFlowDtlCd("0");
            nodeDO.setNodeName(nodeName);
            nodeDO.setStartTime(baseVO.getStartTime());
            nodeDO.setStatusCd("0");
            nodeDO.setRemark(baseVO.getRemark());
            nodeDO.setSortId(String.valueOf(index));
            nodeDO.setCreator(SecurityFrameworkUtils.getLoginUserId().toString());
            nodeDO.setDeleted(false);
            nodeMapper.insert(nodeDO);
            Long preId = nodeDO.getId();
            index++;
            // 保存子节点信息
            if (StrUtil.isNotEmpty(nextIds)) {
                houseService.saveNextIdsData(flowDO.getId(), flowDO.getHouseId(), preId, flowDO.getDesignerId(), "0", subNextIds);
            }
        }
        // 保存图片
        PicDO picDo = new PicDO();
        picDo.setHouseId(flowDO.getHouseId());
        picDo.setFlowId(flowDO.getId());
        picDo.setUploadType("0");
        picDo.setSourceType("0");
        picService.savePicData(picDo, baseVO.getFileList());
        picDo.setUploadType("1");
        picService.savePicData(picDo, baseVO.getDocList());
        // 发起采购任务待办
        createFlowTask(flowDO);

    }

    /**
     * 发起采购任务待办
     * @param flow flow
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createFlowTask(FlowDO flow){
        QueryWrapper<NodeDO> preNodeListQuery = new QueryWrapper();
        preNodeListQuery.eq("flow_id",flow.getId());
        preNodeListQuery.eq("pre_id",0);
        preNodeListQuery.eq("status_cd",0);
        List<NodeDO> preNodeList = nodeMapper.selectList(preNodeListQuery);
        for (NodeDO nodeDo:preNodeList  ) {
            // 将首节点置为进行中
            nodeDo.setStatusCd("1");
            nodeMapper.updateById(nodeDo) ;
            // 查询当前流程子节点的第一个节点 直到最后一个节点
            // 并将每个子节点的首节点  改为进行中
            NodeDO nodeFirstItem = flowTaskService.getNodeFirstItem(nodeDo.getId());
            flowTaskService.saveFlowTask(flow.getHouseId(),flow.getId(),nodeFirstItem);
        }
    }

    /**
     * @param id
     * @return
     */
    @Override
    public Map<String, Object> getNodeInfoById(Long id) {

        return nodeMapper.getNodeInfoById(id);
    }

    /**
     * 查询施工进度
     * 计算方式：施工流程完成节点数/总节点数
     *
     * @param houseId
     * @return result
     */
    @Override
    public double getBuildProcess(Long houseId) {
      // 查询施工流程信息
        FlowBaseVO flowBaseVO = new FlowBaseVO();
        flowBaseVO.setHouseId(houseId);
        flowBaseVO.setFlowCd(FlowCdEnum.FLOW_CD_2.getCode());
        List<FlowDO> flow = flowService.getFlow(flowBaseVO);
        if(flow.size()>0){
            FlowDO flowDO = flow.get(0);
            Long flowId = flowDO.getId();
            // 查询项目施工流程总任务数
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("house_id",houseId);
            queryWrapper.eq("flow_id",flowId);
            Long nodeTotal = nodeMapper.selectCount(queryWrapper);
            if(ObjectUtil.isNull(nodeTotal)||nodeTotal==0){
                return 0;
            }
            queryWrapper.eq("status_cd","2");
            // 查询完成任务总数
            Long precessTotal = nodeMapper.selectCount(queryWrapper);
            double result = NumberUtil.mul(NumberUtil.div(precessTotal, nodeTotal, 4), 100).doubleValue();
            return result;

        }

        return 0;
    }

    @Override
    public Long getNodeCountByFlowId(Long houseId, Long flowId) {
        QueryWrapper<NodeDO> objectQueryWrapper = new QueryWrapper<NodeDO> ();
        objectQueryWrapper.eq("house_id",houseId);

        objectQueryWrapper.eq("flow_id",flowId);

        return nodeMapper.selectCount(objectQueryWrapper);
    }


    /**
     * 开启任意节点任务
     * @param nodeId
     */
    public  void openNodeTaskByNodeId(Long nodeId){
        QueryWrapper queryWrap = new QueryWrapper();
        queryWrap.eq("id",nodeId);

        final NodeDO nodeDO1 = nodeMapper.selectOne(queryWrap);
        // 判断当前登录人是否为 项目内关联人
        final Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        // 先判断当前操作人是否是项目的关联人(状态正常)  不是 报错
        QueryWrapper<UserFlowRelDO> queryUserRel = new QueryWrapper<>();
        queryUserRel.eq("user_id",loginUserId);
        queryUserRel.eq("flow_id",nodeDO1.getFlowId());
        queryUserRel.eq("status", UserRelStatusCdEnum.USER_REL_STATUS_CD_1.getCode());
        final Long aLong = userFlowRelMapper.selectCount(queryUserRel);

        if(aLong<=0){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NO_AUTHORITY_OPTION_BY_PROJECT);
//            throw new NullPointerException("非本项目人员无权限操作");
        }

        if(!"0".equals(nodeDO1.getStatusCd())){
            log.debug( " 已开启");
            return ;
        }
        // 将指定节点  开启
        NodeDO   nextIdTaskNodeDo = flowTaskService.getNodeFirstItem(nodeDO1.getId());
        if(nextIdTaskNodeDo==null){
            nextIdTaskNodeDo = nodeDO1;
        }
        // 生成子节点的待办任务 同时将子节点  改为进行中
        flowTaskService.saveFlowTask(nextIdTaskNodeDo.getHouseId(),nextIdTaskNodeDo.getFlowId(),nextIdTaskNodeDo);
        nextIdTaskNodeDo.setStartTime(new Date());
        nextIdTaskNodeDo.setStatusCd("1");
        nodeMapper.updateById(nextIdTaskNodeDo);

        /*上级节点 修改为进行中*/
        updatePreNodeStatus(nodeDO1.getId(),"1");
    }

    public void updatePreNodeStatus(Long nodeId,String status){
        QueryWrapper queryWrap = new QueryWrapper();
        queryWrap.eq("id",nodeId);

        final NodeDO nodeDO1 = nodeMapper.selectOne(queryWrap);
        nodeDO1.setStartTime(new Date());
        nodeDO1.setStatusCd("1");
        nodeMapper.updateById(nodeDO1) ;

        if(!"0".equals(nodeDO1.getPreId().toString())){
            updatePreNodeStatus(nodeDO1.getPreId(),status);
        }


    }
    @Override
    /**
     * 生成施工流程任务节点
     * @param processVo 勾选的流程模板 数据
     */
    public void createConstructionProcess(NodeConstrucProcessVo processVo){

            //  2. 查询对应施工流程的 flowId
            //  1.判断角色是否是项目关联人、 设计师或者项目经理
            //  3.根据flowMdIds 查询施工流程模板
            //  4.循环创建父节点，判断子节点id 是否在选中的ids 中 不在则不创建
            //   5.开启第一节点任务  发送待办任务
        FlowBaseVO flowBaseVO = new FlowBaseVO();
        flowBaseVO.setHouseId(processVo.getHouseId());
        flowBaseVO.setFlowCd(FlowCdEnum.FLOW_CD_2.getCode());
        List<FlowDO> flowList = flowService.getFlow(flowBaseVO);
        if(CollUtil.isEmpty(flowList)){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.SG_FLOW_NOT_CREATE);
        }
        // 判断当前登录人是否为 项目内关联人
        final Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        // 先判断当前操作人是否是项目的关联人(状态正常)  不是 报错
        QueryWrapper<UserFlowRelDO> queryUserRel = new QueryWrapper<>();
        queryUserRel.eq("house_id",processVo.getHouseId());
        queryUserRel.eq("user_id",loginUserId);
        queryUserRel.eq("flow_id",flowList.get(0).getId());
        queryUserRel.eq("status", UserRelStatusCdEnum.USER_REL_STATUS_CD_1.getCode());
        final Long aLong = userFlowRelMapper.selectCount(queryUserRel);

        if(aLong<=0){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NO_AUTHORITY_OPTION_BY_PROJECT);
//            throw new NullPointerException("非本项目人员无权限操作");
        }
        //校验 施工流程节点数据是否已经创建
        QueryWrapper queryCount = new QueryWrapper();
        queryCount.eq("house_id",processVo.getHouseId());
        queryCount.eq("flow_id",flowList.get(0).getId());
        Long aLong1 = nodeMapper.selectCount(queryCount);
        if(aLong1>0){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.SG_FLOW_NODE_IS_CREATE);
        }
        // 查询项目关联人关系
//        queryUserRel = new QueryWrapper<>();
//        QueryWrapper queryUserFlowRel = new QueryWrapper<>();
//        queryUserFlowRel.eq("house_id",processVo.getHouseId());
//        queryUserFlowRel.eq("flow_id",flowList.get(0).getId());
//        queryUserFlowRel.eq("role_id",DesignUserRoleEnum.PROJECT_MANAGER.getRoleId());
//        queryUserFlowRel.in("status",UserFlowRelStatusCdEnum.USER_REL_STATUS_CD_0.getCode().toString(),
//                UserFlowRelStatusCdEnum.USER_REL_STATUS_CD_1.getCode().toString());
//        List<UserFlowRelDO> userFlowRelDOS =houseUserRelMapper.selectList(queryUserFlowRel);

        // 查询 施工流程项目经理
        QueryWrapper<HouseUserRelDO> queryHouseUserRel = new QueryWrapper<HouseUserRelDO>();
        queryHouseUserRel.eq("house_id",processVo.getHouseId());

        queryHouseUserRel.eq("role_id",DesignUserRoleEnum.PROJECT_MANAGER.getRoleId());
        queryHouseUserRel.in("status",UserFlowRelStatusCdEnum.USER_REL_STATUS_CD_0.getCode().toString(),
                UserFlowRelStatusCdEnum.USER_REL_STATUS_CD_1.getCode().toString());
        List<HouseUserRelDO> hosueUserRelDOS = houseUserRelMapper.selectList(queryHouseUserRel);
        if(CollUtil.isEmpty(hosueUserRelDOS)){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROJECT_MANAGER_NOT_SETTING);
        }
        // 获取施工流程 数据对象
        FlowDO flowDO = flowList.get(0);
        // 查询施工流程模板数据对象
        List<FlowMdDO> flowMdList = flowMdService.getFlowMdList(processVo.getIds());
        NodeItemDataBO context = new NodeItemDataBO();
        context.setHouseId(processVo.getHouseId());
        context.setFlowId(flowDO.getId());
        context.setDesignerId(flowDO.getDesignerId());
        context.setFlowCd(flowDO.getFlowCd());
        context.setList(flowMdList);
        context.setDealerId(hosueUserRelDOS.get(0).getUserId());
        context.setFlowMdIds(processVo.getIds());
        context.setOptionData(processVo.getOptionData());
        houseService.saveNodeItemData(context);

    }


}
